home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 007 / vtkerma1.arc / MSKERM.ASM < prev    next >
Assembly Source File  |  1986-02-13  |  56KB  |  2,295 lines

  1.     PAGE 59, 132
  2.  
  3.     TITLE MSKERM -- Main module for MS-Kermit and descendents
  4.  
  5. ; Update 20 Jan 86
  6.  
  7. IF1
  8.  %OUT >> Starting pass 1
  9. ELSE
  10.  %OUT >> Starting pass 2
  11. ENDIF
  12.  
  13.     PUBLIC Prompt, DosNum, CurDsk, SwChar, Kermit, KrmRet, OldStk
  14.     PUBLIC SPath, PC_Type, PC_Subtype, Dos_Minor, TakRd, NoInt, OkInt
  15.     PUBLIC Get_memory_block, Quick_Push, Exit2, In_menu_mode
  16.     PUBLIC TakAdr, TakLev, Force_mono
  17.  
  18. Code    SEGMENT PARA PUBLIC
  19. Code    ENDS
  20.  
  21. DataS    SEGMENT PARA PUBLIC 'datas'
  22. DataS    ENDS
  23.  
  24. Stack    SEGMENT PARA STACK 'STACK'
  25. Stack    ENDS
  26.  
  27.     INCLUDE MsDefs.H
  28.  
  29. ; Based on ...
  30.  
  31. ;******************** Version 2.26 **********************************
  32. ; KERMIT, Celtic for "free"
  33. ;
  34. ; The name "Kermit" is a registered trade mark of Henson Associates, Inc.,
  35. ; used by permission
  36. ;
  37. ;       Kermit-MS Program Version 2.26, July 26, 1984
  38. ;
  39. ;       Based on the Columbia University KERMIT Protocol
  40. ;
  41. ;       Copyright (C) 1982,1983,1984 Trustees of Columbia University
  42. ;
  43. ;       Daphne Tzoar, Jeff Damens
  44. ;       Columbia University Center for Computing Activities
  45. ;       612 West 115th Street
  46. ;       New York, NY  10025
  47. ;
  48. ; Special thanks to Frank da Cruz, Bill Catchings, Steve Jensen, Herm Fischer,
  49. ; Vace Kundakci, and Bernie Eiben for their help and contributions
  50.  
  51. makseg    EQU 26H
  52. deffcb    EQU 5cH
  53. setblk    EQU 4AH
  54. exec    EQU 4BH
  55. env    EQU 2CH            ; environment address in psp
  56. cline    EQU 80H            ; offset in psp of command line
  57. namsiz    EQU 64            ; Bytes for file name and size
  58. maxnam    EQU 10
  59. chmod    EQU 43H            ; chmod call (used to test for file existence)
  60.  
  61. DataS    SEGMENT PUBLIC 'datas'
  62.  
  63.     EXTRN DTA:byte, comand:byte, flags:byte, pack:byte, trans:byte
  64.     EXTRN fcb:byte, cpfcb:byte, prmptr:word, inichk:byte
  65.  
  66. Help_text db Cr,Lf
  67.     Program_name
  68.     DB ' is an enhanced version of Columbia '
  69.     db "University's MS-Kermit program.",Cr,Lf,'This version supports '
  70.     db 'IBM PCs and compatibles as well as the DEC Rainbow.',Cr,Lf,Cr,Lf
  71.  
  72.     Program_name
  73.     db ' has two main functions:  Terminal Emulation and File '
  74.     db 'Transfer.  In',Cr,Lf,'Terminal Emulation Mode, '
  75.     Program_name
  76.     DB ' permits '
  77.     db 'your microcomputer to act as a DEC',Cr,Lf,'VT100 terminal. '
  78.     db ' In File Transfer Mode, '
  79.     Program_name
  80.     DB ' permits you to exchange files'
  81.     db Cr,Lf,'with a remote computer running a program which '
  82.     db 'supports the Kermit file',Cr,Lf,'transfer protocol.  '
  83.     db 'A third mode, Command Mode, is used to set parameters and '
  84.     db Cr,Lf,'control the program.  Press ? while '
  85.     db 'typing a command for help, or press Esc',Cr,Lf
  86.     db 'for command completion.',Cr,Lf,Cr,Lf
  87.  
  88.     db 'To use Terminal Emulation, you must first specify (or default) '
  89.     db 'all required',Cr,Lf,'parameters (PORT, BAUD rate, and PARITY),'
  90.     db " then press the IBM PC's F5 key ",'("Do"',Cr,Lf,'on Rainbow).  '
  91.     db 'To get back to Command Mode, press F5 or Do again.  While in'
  92.     db Cr,Lf,'Terminal Mode you can press F6 (PC only) '
  93.     db 'to get more help.',Cr,Lf,Cr,Lf
  94.  
  95.     db 'To use File Transfer:',Cr,Lf
  96.     db '  1)  Establish a connection to a remote host computer;',Cr,Lf
  97.     db '  2)  Run Kermit (or a Kermit-based program) on the host in '
  98.     db 'SERVER mode;',Cr,Lf
  99.     db '  3)  Enter local Command Mode and type "SEND filename" to '
  100.     db 'send a file,',Cr,Lf
  101.     db '        or "GET filename" to receive a file from the host.'
  102.     db Cr,Lf,Cr,Lf,'$'
  103.  
  104. versio    DB cr, lf        ; Leading CrLf
  105.     verdef
  106.     DB ' running $'
  107.  
  108. On    DB 'on $'
  109. IBMsg    DB 'IBM PC$'
  110. RbMsg    DB 'DEC Rainbow$'
  111. GrMsg    DB 'GRiD GRiDCase$'
  112. Att6300Msg DB 'AT&T 6300$'
  113. QuadRamsg DB 'QuadRam DataVue$'
  114. MSDOS    DB 'under MS-DOS$'
  115. UkMsg    DB 'MS-DOS OEM #$'
  116.  
  117. XT_str    DB '/XT$'
  118. Portable_str DB ' Portable$'
  119. jr_str    DB 'jr$'
  120. AT_str    DB ' AT$'
  121. Compaq_str DB ' clone (Compaq)$'
  122. Clone_str DB ' clone (?)$'
  123.  
  124. ;    DB ' under DOS v'
  125. ;dosvers DB '9.99'
  126.  
  127. EndVersio DB '  --  type ? or HELP for help',cr,lf,cr,lf,'$'
  128.  
  129. tmp    db ?,'$'
  130. crlf    db cr,lf,'$'
  131. ermes1  db '? Unrecognized command',cr,lf,'$'
  132. ermes3  db '? Not confirmed',cr,lf,'$'
  133. erms30    db '? Passed maximum nesting level for TAKE command',cr,lf,'$'
  134. erms31    db '? File not found',cr,lf,'$'
  135. erms32    db '? File(s) not found',cr,lf,'$'
  136. erms33    db '? CHKDSK program not found on current disk',cr,lf,'$'
  137. erms34    db '? This program runs only under DOS 2.0 and above',cr,lf,'$'
  138. erms35    db '? Must specify program name',cr,lf,'$'
  139. erms36    db '? Could not free memory',cr,lf,'$'
  140. erms37    db '? Unable to execute program',cr,lf,'$'
  141. erms38    db '? Not enough TAKE stack space left to parse filename',cr,lf,'$'
  142. infms1    db 'Really erase *.*? $'
  143. infms8    db 'File(s) erased',cr,lf,'$'
  144. Echo_help DB ' Text to be echoed on screen$'
  145. tmsg5    db '[Closing log file]',cr,lf,'$' ; [jd]
  146. filhlp1 db ' Command file specification $'
  147. filhlp2 db ' File specification (possibly wild) $'
  148. filhlp3    db ' File spec (possibly wild) or confirm with carriage return$'
  149. filmsg    db ' File specification with optional path name $'
  150. filwmsg    db ' File specification (possibly wild) with optional path name $'
  151. chkfil    db 0,'CHKDSK  COM'
  152. chkflen    EQU $-chkfil
  153.  
  154. tophlp    DB ' One of the following:'
  155.     DB cr,lf,' '
  156.     DB 'BYE',tab,tab
  157.     DB 'CLOSE',tab,tab
  158.     DB 'CLS',tab,tab
  159.     DB 'CONNECT'
  160.     DB cr,lf,' '
  161.     DB 'DEFINE',tab,tab
  162.     DB 'DELETE',tab,tab
  163.     DB 'DIRECTORY',tab
  164.     DB 'DO'
  165.     DB cr,lf,' '
  166.     DB 'DO-SCRIPT',tab
  167.     DB 'DROP-DTR',tab
  168.     DB 'ECHO',tab,tab
  169.     DB 'EXIT'
  170.     DB cr,lf,' '
  171.     DB 'FINISH',tab,tab
  172.     DB 'GET',tab,tab
  173.     DB 'HELP',tab,tab
  174.     DB 'LOCAL'
  175.     DB cr,lf,' '
  176.     DB 'LOG',tab,tab
  177.     DB 'LOGOUT',tab,tab
  178.     DB 'MENU',tab,tab
  179.     DB 'NPSEND'
  180.     DB cr,lf,' '
  181.     DB 'PUSH',tab,tab
  182.     DB 'QUIT',tab,tab
  183.     DB 'RECEIVE',tab,tab
  184.     DB 'REMOTE'
  185.     DB cr,lf,' '
  186.     DB 'RUN',tab,tab
  187.     DB 'SCRIPT-FILE',tab
  188.     DB 'SEND',tab,tab
  189.     DB 'SERVER'
  190.     DB cr,lf,' '
  191.     DB 'SET',tab,tab
  192.     DB 'SHOW',tab,tab
  193.     DB 'SPACE',tab,tab
  194.     DB 'STATUS'
  195.     DB cr,lf,' '
  196.     DB 'TAKE',tab,tab
  197.     DB 'XRECEIVE',tab
  198.     DB 'XSEND'
  199.     DB '$'
  200.  
  201. lochlp    DB cr,lf,' DELETE file'
  202.     DB cr,lf,' DIRECTORY [filespec]'
  203.     DB cr,lf,' PUSH to command interpreter'
  204.     DB cr,lf,' RUN program'
  205.     DB cr,lf,' SPACE remaining on current disk'
  206.     DB '$'
  207.  
  208.     ; COMND tables
  209.  
  210. yestab    DB 2
  211.     mkeyw    'NO',0
  212.     mkeyw    'YES',1
  213.  
  214. comtab  DB 36
  215.     mkeyw    'BYE',bye
  216.     mkeyw    'C',telnet
  217.     mkeyw    'CLOSE',clscpt
  218.     mkeyw    'CLS',Clear_screen
  219.     mkeyw    'CONNECT',telnet
  220.     mkeyw    'DEFINE',dodef
  221.     mkeyw    'DELETE',delete
  222.     mkeyw    'DIRECTORY',direct
  223.     mkeyw    'DO',docom
  224.     mkeyw    'DO-SCRIPT', Do_Script
  225.     mkeyw    'DROP-DTR',DoDrop
  226.     mkeyw    'ECHO', Echo_command
  227.     mkeyw    'EXIT',exit
  228.     mkeyw    'FINISH',finish
  229.     mkeyw    'GET',get
  230.     mkeyw    'HELP',help
  231.     mkeyw    'LOCAL',lclcmd
  232.     mkeyw    'LOG',setcpt
  233.     mkeyw    'LOGOUT',logout
  234.     mkeyw    'MENU', Menu
  235.     mkeyw    'NPSEND', Non_protocol_send
  236.     mkeyw    'PUSH',dopush
  237.     mkeyw    'QUIT',exit
  238.     mkeyw    'RECEIVE',read
  239.     mkeyw    'REMOTE',remote
  240.     mkeyw    'RUN',run
  241.     mkeyw    'SCRIPT-FILE', Script_File
  242.     mkeyw    'SEND',send
  243.     mkeyw    'SERVER',server
  244.     mkeyw    'SET',setcom
  245.     mkeyw    'SHOW',showcmd
  246.     mkeyw    'SPACE',chkdsk
  247.     mkeyw    'STATUS',status
  248.     mkeyw    'TAKE',take
  249.     mkeyw    'XRECEIVE', XReceive
  250.     mkeyw    'XSEND', XSend
  251.  
  252. loctab    DB 5
  253.     mkeyw    'DELETE',delete
  254.     mkeyw    'DIRECTORY',direct
  255.     mkeyw    'PUSH',dopush
  256.     mkeyw    'RUN',run
  257.     mkeyw    'SPACE',chkdsk
  258.  
  259. shotab    DB 2
  260.     mkeyw    'KEY',shokey
  261.     mkeyw    'MACRO',shomac
  262.  
  263. ; Program storage
  264.  
  265. Hold_di    DW ?            ; Place to hold di reg over call to COMND
  266.  
  267. oldstk  DW ?            ; Storage for system stack
  268. oldsts  DW ?             ; System stack segment
  269. ssave    DW ?            ; Original SS when doing CHKDSK
  270. siz    DW ?            ; Memory size
  271. in3ad    DD 0            ; Original break interrupt addresses. [25]
  272. curdsk    DB 0            ; Current disk
  273. origd    DB 0            ; Original disk
  274. fildat    DB 0            ; Manipulate file data/time creation
  275.     DB 0
  276. taklev    DB 0            ; Take levels. [25t]
  277. takadr    DW takstr-(size takinfo) ; Pointer into structure. [25t]
  278. temp    DW 0
  279. temp1   DW ?             ; Temporary storage
  280. temp2   DW ?
  281. temp3   DW ?
  282. temp4   DW ?
  283. psp    DW ?
  284. divst    DW 0
  285.  
  286. Max_count_of_blocks=10        ; Size of memory block table
  287. Count_of_allocated_blocks DW 0    ; Number of entries in memory block table
  288. Block_table DW Max_count_of_blocks DUP (0) ; Memory block table
  289.  
  290. PC_Type    DB 0            ; Zero for IBM
  291.                 ;  2 for Rainbow
  292.                 ;  4 for GRiD GRiDCase
  293.                 ;  6 for AT&T 6300
  294.                 ;  8 for QuadRam DataVue
  295.                 ;  20 for unknown hardware (crash is likely)
  296. PC_Subtype DB 0            ; Zero for vanilla PC,
  297.                 ;  1 for PC/XT
  298.                 ;  2 for PCjr
  299.                 ;  3 for PC AT
  300.                 ;  4 for Portable PC
  301.                 ;  90 for Compaq
  302.                 ;  99 for PC clones
  303.  
  304. takstr    DB (size takinfo) * maxtak dup(?)
  305.  
  306.  
  307. ; Build a 12 char FCB style INI file name
  308.  
  309. ininam    DB 0
  310. IniXXX    DB '        INI'    ; Start with 8 spaces followed by INI
  311. IniYYY    LABEL BYTE        ; A label following the base name
  312.     ORG IniXXX        ; Go back to where the 8 space are
  313.     Program_name        ; Overlay the start with our file name
  314.     ORG IniYYY        ; Go back to proper location
  315.  
  316.  
  317. ; Build a DOS 2.0 style INI file name
  318.  
  319. IniNm2    LABEL    BYTE
  320.     Program_name
  321.     DB '.INI',0    ; Name of INIT file
  322. IniNm2_len EQU $ - IniNm2
  323.  
  324. nambuf    DB maxnam * namsiz dup (?)
  325. cmdnam    DB namsiz dup (?)
  326. exefcb    DB fcbsiz dup (?)
  327. exefcb2    DB fcbsiz dup (?)
  328. exearg    DW ?            ; segment addr of environment (filled in below)
  329.     DD 0            ; ptr to cmd line (filled in below)
  330.     DD exefcb        ; default fcb
  331.     DD exefcb2        ; second default fcb
  332. dircmd    DB ' /c dir '
  333. dirclen    EQU $-dircmd
  334. dirnam    DB 50h dup (?)
  335. chkdcmd    DB 'chkdsk.com'
  336. chkdlen    EQU $-chkdcmd
  337. dosnum    DB ?            ; dos version number
  338. Dos_Minor DB ?            ; Dos minor version number
  339. Force_mono DB ?            ; Use monochrome attributes on color displays
  340. pthnam    DB 'PATH='
  341. pthlen    EQU $-pthnam
  342. pthbuf    DB 160 dup (?)        ; buffer for path definition
  343. defpth    DB '\', 70 dup (?)    ; buffer for default path
  344. cmspnam    DB 'COMSPEC='
  345. cmsplen    EQU $-cmspnam
  346. cmspbuf    DB '\command.com', 0    ; Default name
  347.     DB 30 dup (?)        ; Some additional space
  348. TFile    DB 100 dup (?)        ; Temp space for file names
  349. swchar    DB '\'            ; Default switch character
  350.  
  351. In_menu_mode DB 0        ; If non-0, we are in menu (not command) mode
  352. NoInt_Count DB 0        ; Number of times we have been NoInt-ed
  353. LastChar DB 0            ; Last char we read in NPSEND
  354.  
  355. Number    DB 8 DUP (?)        ; Place to hold a number
  356.  
  357. DataS    ENDS
  358.  
  359.  
  360. Code    SEGMENT    PUBLIC
  361.  
  362.     EXTRN cmblnk:near, locate:near, logout:near, Drop_DTR:NEAR
  363.     EXTRN bye:near, telnet:near, finish:near, comnd:near, Telnet2:NEAR
  364.     EXTRN read:near, remote:near, send:near, status:near, get:near
  365.     EXTRN dodisk:near, serrst:near, setcom:near, OutChr:NEAR
  366.     EXTRN clscpi:near, clscpt:near, getbaud:near, dodef:near, setcpt:near
  367.     EXTRN docom:near, Set_up_script_processor:NEAR, server:near, lclini:near
  368.     EXTRN shokey:near, shomac:near, XReceive:NEAR, XSend:NEAR
  369.     EXTRN Script_File:NEAR, Do_Script:NEAR, Menu:NEAR, Quick_menu:NEAR
  370.  
  371.     ASSUME cs:Code, ds:Datas, ss:Stack
  372.  
  373. Critical DD ?            ; Address of original Critical Error Handler
  374.  
  375. Error_handling_installed DB 0    ; Flag set if error handling has been installed
  376. Last_Critical_Error DW 00FFh    ; Most recent critical error, if any
  377.  
  378. Start   PROC FAR
  379.  
  380.     push ds            ; Save system data area
  381.     sub ax,ax         ; Get a zero
  382.     push ax            ; Put zero return addr on stack
  383.  
  384.     mov ax, SEG DataS    ; Initialize DS
  385.     mov ds,ax
  386.     sub ax,ax
  387.  
  388.     mov oldstk, sp        ; Save old stack pointer
  389.  
  390.     mov ax,es:[2]        ; In program segment prefix
  391.     mov siz,ax        ; Pick up memory size
  392.     mov psp,es
  393.  
  394.     mov ax, ds        ; Copy ds
  395.     mov es, ax        ;  to es
  396.  
  397.     ASSUME es:datas
  398.  
  399.     mov ah, 30h        ; Code to get DOS version number
  400.     int Dos            ; Do it
  401.     cmp al, 2        ; DOS 2.0 or higher?
  402.      jae DOS_is_Ok        ;  Not a problem
  403.  
  404.     mov ah, PrStr        ; Code to print a string
  405.     mov dx, OFFSET ErMs34    ; Message complaining about lousy DOS
  406.     int Dos            ; Type it
  407.  
  408.     ret            ; Return to DOS
  409.  
  410. DOS_is_Ok:
  411.     mov ax, (33H * 256) + 1    ; Code to set BREAK state
  412.     sub dl, dl        ; Force it off NOW!
  413.     int Dos            ; We use ^C heavily, we have to control it
  414.  
  415.     push es            ; Save es register
  416.     mov es, psp        ; Point to psp again
  417.     mov ax, es:[Env]    ; Get environment ptr
  418.     mov exearg, ax        ; Put into argument block
  419.  
  420. ; Give back memory which we don't need from our initial allocation
  421. ;  (DOS gives us all available memory)
  422.  
  423.     mov bx, OFFSET Stk + 15    ; End of program
  424.     mov cl, 4
  425.     shr bx, cl        ; Compute # of paragraphs in last segment
  426.  
  427.     mov ax, SEG stack    ; Last segment, either alphabetically or
  428.                 ;  sequentially
  429.     sub ax, Psp        ; Minus beginning..
  430.  
  431.     add bx, ax        ; # of paragraphs occupied
  432.     mov ah, SetBlk        ; Try to change size of our memory block
  433.     int Dos            ; Success?
  434.      jnc SHS_1        ;  Nope..
  435.  
  436.     pushf            ; Save flags
  437.     mov ah, PrStr
  438.     mov dx, OFFSET ErMs36    ; Complain
  439.     int Dos
  440.     popf            ; Restore flags
  441.  
  442. SHS_1:    pop es            ; Unclobber register
  443.  
  444. ; Before beginning, establish our own quick-o shortcut in case a drive
  445. ;  on the PATH is without disk ... in that case, just bomb the call, don't
  446. ;  do the usual "Abort, Retry or Ignore"
  447.  
  448.     call Set_up_error_handling ; Establish our routine as the one to use
  449.  
  450.     mov ah, prstr        ; Print start of version header
  451.     mov dx, OFFSET Versio
  452.     int Dos
  453.  
  454.  
  455. ; Get the DOS version number and the "vendor number" for the vendor of this
  456. ;  copy of DOS ... anytime we are running PC-DOS (on whatever machine) we think
  457. ;  we are on "an IBM".  If the user thinks PC-DOS runs on his machine, lets
  458. ;  assume that the machine is a perfect enough clone for our purposes ...
  459.  
  460.     PUBLIC See_what_machine_we_are_on
  461.  
  462. See_what_machine_we_are_on:
  463.     mov ah, 30h        ; Code to get DOS version & vendor numbers
  464.     int Dos            ; Do it
  465.  
  466.     mov dosnum, al        ; Remember major Dos version
  467.     mov Dos_Minor, ah    ; Store minor version number also
  468.  
  469.     mov Force_mono, 0    ; Default to "use color on color display"
  470.     mov ah, PrStr        ; Set up to type strings
  471.  
  472.     PUBLIC Check_vendor
  473.  
  474. Check_vendor:
  475.     cmp bh, 0FFh        ; Generic MS-DOS?
  476.      jne Not_MSDOS        ;  No
  477.  
  478.     mov dx, OFFSET MSDOS    ; "under MS-DOS"
  479.     int Dos            ; Type it
  480.     jmp SHORT Finish_banner    ; Go finish it up
  481.  
  482. Not_MSDOS:
  483.     mov dx, OFFSET On    ; "on "
  484.     int Dos            ; Type it
  485.     cmp bh, 0        ; Is the vendor IBM?
  486.      jne Not_IBM        ;  No
  487.  
  488.     call Vendor_is_IBM    ; Use special rtn to determine type of IBM
  489.     jmp SHORT Finish_banner    ; Go finish it up
  490.  
  491. Not_IBM: cmp bh, 16h        ; Is the vendor DEC?
  492.       jne Not_DEC        ;  No
  493.  
  494.     mov PC_Type, 2        ; Type is DEC
  495.     mov dx, OFFSET RbMsg    ; DEC Rainbow
  496.     int Dos
  497.     jmp SHORT Finish_banner
  498.  
  499. Not_DEC: cmp bh, 2Eh        ; Is the vendor GRiD?
  500.       jne Not_GRiD        ;  No
  501.  
  502.     mov PC_Type, 4        ; Type is GRiD
  503.     mov dx, OFFSET GrMsg    ; GRiD GRiDCase
  504.     int Dos
  505.     jmp SHORT Finish_banner
  506.  
  507. Not_GRiD: cmp bh, 77h        ; Is the vendor AT&T?
  508.       jne Not_Att        ;  No
  509.  
  510.     mov PC_Type, 6        ; Type is AT&T 6300
  511.     mov dx, OFFSET Att6300Msg
  512.     int Dos
  513.     jmp SHORT Finish_banner
  514.  
  515.     PUBLIC No_body
  516.  
  517. Not_Att: cmp bh, 60        ; Is the vendor QuadRam?
  518.       jne No_body        ;  No
  519.  
  520.     mov PC_Type, 8        ; Type is QuadRam DataVue 25
  521.     mov dx, OFFSET QuadRamsg
  522.     int Dos
  523.     jmp SHORT Finish_banner
  524.  
  525.     PUBLIC No_body
  526.  
  527. No_body:
  528.     push bx            ; Save reg
  529.     mov PC_Type, 20        ; Type is unknown
  530.     mov dx, OFFSET UkMsg    ; Unknown hardware
  531.     int Dos
  532.  
  533.     pop bx            ; Get back reg
  534.     cld            ; Forwards
  535.     mov al, bh        ; Copy OEM # to al
  536.     mov ah, 0        ; Zero high half
  537.  
  538.     mov di, OFFSET Number    ; Point at Number
  539.     call nout2        ; Do the number
  540.     mov al, '$'        ; Get a dollar sign
  541.     stosb            ; Put it down
  542.  
  543.     mov ah, PrStr        ; Code to type to screen
  544.     mov dx, OFFSET Number    ; Point this at Number
  545.     int Dos            ; Do it
  546.  
  547. Finish_banner:
  548.     mov dx,offset EndVersio ; Close it out
  549.     int dos
  550.  
  551.     mov ah,setdma        ; Set disk transfer address
  552.     mov dx,offset DTA
  553.     int dos
  554.  
  555.     call getbaud        ; Get the baud rate. [25]
  556.     call dodisk        ; See how many disk drives we have. [21a]
  557.     call setint
  558.  
  559.     mov ah,gcurdsk        ; Get current disk
  560.     int dos
  561.  
  562.     inc al            ; We want 1 == A (not zero)
  563.     mov curdsk,al
  564.     mov origd,al        ; Remember original disk we started on
  565.  
  566.     mov es,psp
  567.     mov ax,es:[env]        ; pick up environment address
  568.     push ax
  569.     call getpath        ; get the path from the environment
  570.     pop ax            ; get environment back
  571.     call getcsp        ; get comspec from environment as well
  572.  
  573.     mov Flags.ExtFlg, 0    ; Clear EXIT flag before LCLINI just in case
  574.     call LclIni        ; Do local initialization
  575.     cmp Flags.ExtFlg, 0    ; Some LclIni routines flag fatal errors
  576.      je KrmGo        ;  No, finish startup
  577.  
  578.     jmp KrmEnd        ; If so jump to KRMEND
  579.  
  580. KrmGo:    call gcmdlin        ; read command line
  581.     call rdinit        ; read kermit init file
  582.     call packlen        ; Packet length in case do server comand
  583.  
  584.  
  585. ; This is the main KERMIT loop.  It prompts for and gets the users commands
  586.  
  587. Kermit:    mov ax,ds
  588.     mov es,ax        ; make sure this addresses data segment
  589.  
  590.     mov dx,prmptr        ; get prompt
  591.     call prompt        ; Prompt the user
  592.     mov pack.state,0    ; Clear the state
  593.     mov flags.cxzflg,0    ; Reset each itme
  594.     mov Flags.XFlg, 0    ; This one also [tm]
  595.  
  596.     mov ah, Flags.Real_RemFlg ; Pick this up
  597.     mov Flags.RemFlg, ah    ; Copy to here
  598.  
  599.     mov ah,inichk        ; Original or set checksum length
  600.     mov trans.chklen,ah    ; Reset just in case
  601.     mov dx,offset comtab
  602.     mov bx,offset tophlp
  603.     mov comand.cmcr,1    ; Allow bare CR's
  604.     mov ah,cmkey
  605.     call comnd
  606.      jmp kermt2
  607.     mov comand.cmcr,0    ; Not anymore
  608.     call bx            ; Call the routine returned
  609. krmret:  jmp kermt3
  610.     cmp flags.extflg,0    ;  Check if the exit flag is set
  611.     jne krmend        ;  If so jump to KRMEND
  612.     jmp kermit        ; Do it again
  613.  
  614. kermt2:    mov dx,offset ermes1    ;  Give an error
  615.     jmp short kermt4
  616.  
  617. kermt3:    mov dx,offset ermes3    ;  Give an error
  618. kermt4:    cmp flags.cxzflg,'C'    ; some sort of abort?
  619.     je kermit        ; yes, don't print error message
  620.     mov ah,prstr
  621.     int dos
  622.     mov flags.droflg,0    ; Reset drive override flag
  623.     mov flags.nmoflg,0    ; Reset filename override flag
  624.     mov flags.getflg,0    ; May as well do this one
  625.     mov flags.cmrflg,0    ; This one too
  626.     jmp kermit
  627.  
  628. krmend: call serrst        ; Just in case the port wasn't reset. [21c]
  629.  
  630.     mov dl,origd        ; Original disk drive
  631.     dec dl            ; Want A == 0
  632.     mov ah,seldsk        ; Reset original disk just in case
  633.     int dos
  634.  
  635.     call Return_all_memory    ; Clean up after ourselves
  636.  
  637.     call Restore_normal_error_handling ; Return to normal situation
  638.  
  639.     mov sp, OldStk        ; Fix up stack just in case
  640.  
  641.     mov ax, 4C00h        ; Code to exit with no error
  642.     int Dos            ; Quit to DOS
  643.  
  644.     ret            ; Should not return here!
  645.  
  646. START    ENDP
  647.  
  648.  
  649. ; Special routine to figure out what kind of IBM flavor PC we are running on
  650.  
  651. Vendor_is_IBM:
  652.  
  653.     mov PC_Type, 0        ; Type is IBM
  654.     mov dx, OFFSET IBMsg    ; IBM PC
  655.     int Dos
  656.  
  657.     mov bx, 0FFFFh        ; Highest segment
  658.     push es            ; Save es
  659.     mov es, bx        ; Set up es
  660.     mov al, es:[0Eh]    ; "Machine-Sensitive Code", says IBM
  661.     pop es            ; Restore es
  662.  
  663.     cmp al, 0FFh        ; Vanilla PC?
  664.      jne IBM_0        ;  No, keep working
  665.  
  666.     ret            ; Yes, done here
  667.  
  668. IBM_0:    cmp al, 0FEh        ; PC/XT?
  669.      jne NotXT
  670.  
  671. ; Its down to /XT versus Portable PC (same BIOS)
  672.  
  673.     mov bx, 040h        ; DOS's data segment
  674.     push es            ; Save es
  675.     mov es, bx        ; Set up es
  676.     mov al, es:[075h]    ; Count of fixed disk drives
  677.     pop es            ; Restore es
  678.  
  679.     cmp al, 0        ; Are there any fixed disks on this machine?
  680.      jne IsXT        ;  Yes there are, must be an XT
  681.  
  682.     mov PC_Subtype, 4    ; Type is Portable PC
  683.     mov dx, OFFSET Portable_str
  684.     mov Force_mono, 1    ; Portable has monochrome amber screen
  685.     jmp SHORT Suffix
  686.  
  687. IsXT:    mov PC_Subtype, 1    ; Type is PC/XT
  688.     mov dx, OFFSET XT_str
  689.     jmp SHORT Suffix
  690.  
  691. NotXT:    cmp al, 0FDh        ; PCjr?
  692.      jne Notjr
  693.  
  694.     mov PC_Subtype, 2    ; Type is PCjr
  695.     mov dx, OFFSET jr_str
  696.     jmp SHORT Suffix
  697.  
  698. Notjr:    cmp al, 0FCh        ; PC AT?
  699.      jne NotAT
  700.  
  701.     mov PC_Subtype, 3    ; Type is PC AT
  702.     mov dx, OFFSET AT_str
  703.     jmp SHORT Suffix
  704.  
  705. NotAT:    cmp al, 02Dh        ; Compaq?
  706.      jne NotCompaq
  707.  
  708.     mov PC_Subtype, 90    ; Type is Compaq
  709.     mov dx, OFFSET Compaq_str
  710.     mov Force_mono, 1    ; Compaq has green monochrome screen
  711.     jmp SHORT Suffix
  712.  
  713. NotCompaq:
  714.     mov PC_Subtype, 99    ; Type is PC clone
  715.     mov dx, OFFSET Clone_str
  716.  
  717. Suffix:    int Dos            ; Finish up DOS call
  718.     ret            ; Done here
  719.  
  720.  
  721. ; CLS command -- used to clear the screen
  722.  
  723. Clear_screen PROC
  724.  
  725.     mov ah,cmcfm
  726.     call comnd        ; Get a confirm
  727.      jmp r
  728.  
  729.     call CmBlnk        ; Call routines to clear the screen
  730.     call Locate        ;  then home the cursor ...
  731.  
  732.     jmp RSkp        ; Get the prompt
  733.  
  734. Clear_screen ENDP
  735.  
  736.  
  737. ; DROP-DTR command -- used to hang up the line
  738.  
  739. DoDrop    PROC
  740.  
  741.     mov ah, cmcfm
  742.     call comnd        ; Get a confirm
  743.      jmp r
  744.  
  745.     call SerRst        ; Reset serial port (uninstall interrupt rtn)
  746.     call Drop_DTR        ; Call routine to drop DTR
  747.     jmp RSkp
  748.  
  749. DoDrop    ENDP
  750.  
  751.  
  752. ; ECHO command -- display some text for the user to see
  753.  
  754. Echo_command PROC
  755.  
  756.     mov ah, CMTXT        ; Read in a line of text
  757.     mov bx, OFFSET TFile    ; Temp area for text, max 100 chars
  758.     mov dx, OFFSET Echo_help ; Simple message for help
  759.     call comnd        ; Do it
  760.      jmp RSkp
  761.  
  762.     mov di, OFFSET TFile    ; Point to start of message
  763.     mov bl, ah        ; Copy length to bl
  764.     sub bh, bh        ; Clear high half
  765.     add di, bx        ; Move to end of message
  766.     mov al, Cr        ; Return
  767.     stosb            ; Store it
  768.     mov al, Lf        ; Line feed
  769.     stosb            ; Store it
  770.     mov al, '$'        ; Dollar sign
  771.     stosb            ; Store it
  772.  
  773.     mov dx, OFFSET TFile    ; Point to text again
  774.     mov ah, PrStr        ; Code to type a string
  775.     int Dos            ; Type it
  776.  
  777.     jmp rskp
  778.  
  779. Echo_command ENDP
  780.  
  781.  
  782. ; This is the 'exit' command.  It leaves KERMIT and returns to DOS
  783.  
  784. EXIT    PROC    NEAR
  785.  
  786.     mov ah, cmcfm
  787.     call comnd        ; Get a confirm
  788.      jmp r
  789.  
  790.     test flags.capflg,0FFH    ; capturing?
  791.      jz exit2        ; no, keep going
  792.  
  793.     mov dx,offset tmsg5
  794.     mov ah,prstr
  795.     int Dos
  796.  
  797.     call clscpi
  798.      nop            ; this skip returns..
  799.      nop
  800.      nop
  801.  
  802. exit2:    mov flags.extflg, 1    ; Set the exit flag
  803.     jmp rskp        ; Then return to system
  804.  
  805. EXIT    ENDP
  806.  
  807.  
  808. ; This is the 'help' command.  It gives a very brief intro to the program
  809.  
  810. HELP    PROC    NEAR
  811.     mov ah,cmcfm
  812.     call comnd        ; Get a confirm
  813.      jmp r
  814.     mov ah,prstr        ; Print a string to the console
  815.     mov dx,offset Help_text    ; The address of the help message
  816.     int dos
  817.     jmp rskp
  818. HELP    ENDP
  819.  
  820. lclcmd    proc    near
  821.     mov ah,cmkey
  822.     mov dx,offset loctab
  823.     mov bx,offset lochlp
  824.     call comnd
  825.      jmp r
  826.     call bx
  827.     nop
  828.     nop
  829.     nop
  830.     jmp rskp
  831. lclcmd    endp
  832.  
  833.     PUBLIC SetInt
  834.  
  835. ; Don't ignore ^C when in debug mode
  836. SETINT    PROC    NEAR
  837.  
  838.     push es            ; Save reg
  839.     mov ax, 3523h        ; Want addr for int 23h
  840.     int Dos            ; Get address of this interrupt
  841.  
  842.     mov WORD PTR in3ad, bx    ; Store offset (IP)
  843.     mov ax, es        ; Copy es to ax
  844.     mov WORD PTR in3ad+2, ax ; Store the segment (CS)
  845.     pop es            ; Get back normal es
  846.  
  847.     push ds            ; Save ds
  848.     mov ax, cs        ; Copy cs ...
  849.     mov ds, ax        ;  ... to ds
  850.     mov ax, 2523h        ; Install new addr for int 23
  851.     mov dx, OFFSET IntBrk    ; Addr of routine
  852.     int Dos            ; Store addr of our routine for this interrupt
  853.     pop ds            ; Restore ds
  854.     ret
  855.  
  856. SETINT    ENDP
  857.  
  858. ; NPSEND command -- Non-Protocol SEND of a file
  859.  
  860. Non_protocol_send PROC
  861.  
  862.     cld            ; Forwards
  863.     cmp taklev, maxtak    ; Hit our limit?
  864.      jl NPS_1        ;  Continue if still OK
  865.  
  866.     mov ah,prstr
  867.     mov dx,offset erms38    ; Complain
  868.     int dos
  869.     jmp RSkp
  870.  
  871. NPS_1:    mov di,takadr
  872.     add di,size takinfo
  873.     mov Hold_di, di        ; Save reg
  874.  
  875.     mov ah,cmtxt
  876.     lea bx,[di].takbuf    ; convenient place to parse name into
  877.     mov dx,offset filmsg    ; Help in case user types "?"
  878.     call comnd        ; Parse for a text string
  879.      jmp RSkp        ;  Can't get text string (?), give up
  880.  
  881.     mov di, Hold_di        ; Restore reg
  882.     lea si,[di].takbuf    ; get buffer back
  883.     mov bl,ah        ; length of thing parsed
  884.     sub bh, bh        ; Zero top half
  885.     mov byte ptr [bx+si],0    ; make it asciz
  886.     mov ax,si        ; point to name again
  887.     call spath        ; is it around?
  888.      jc NPS_2        ; no, go complain
  889.  
  890.     mov di, Hold_di        ; Restore reg
  891.     mov dx,ax        ; point to name from spath
  892.     mov ah,open2        ; 2.0 open call
  893.     mov al,0        ; open for reading
  894.     int dos
  895.      jnc NPS_3        ; open ok, keep going
  896.  
  897. NPS_2:    mov ah,prstr
  898.     mov dx,offset erms31
  899.     int dos
  900.     jmp RSkp
  901.  
  902. NPS_3:    inc taklev
  903.     mov takadr,di
  904.     mov word ptr [di].takfcb+1,ax    ; save file descriptor
  905.     mov byte ptr [di].takfcb,0feh    ; mark as 2.0 file descriptor
  906.  
  907.     mov bx, ax        ; need descriptor here
  908.     mov ax, (LSeek*256)+2
  909.     sub cx, cx
  910.     mov dx, cx        ; seek 0 bytes from end
  911.     int dos
  912.  
  913.     mov [di].takcnt,ax
  914.     mov [di].takcnt+2,dx    ; store length
  915.  
  916.     mov ax, (LSeek*256)+0
  917.     sub cx, cx
  918.     mov dx, cx        ; now seek back to beginning
  919.     int dos
  920.  
  921.     call takrd        ; Get a buffer full of data
  922.  
  923.     mov ax, OFFSET cs:Our_entry_point ; Get address of our entry point
  924.     call Set_up_script_processor ; Tell emulator to call us (and where)
  925.  
  926.     call Telnet2        ; Enter terminal emulator
  927.      nop            ;  Ignore skip return
  928.      nop
  929.      nop
  930.  
  931.     jmp RSkp        ; All done
  932.  
  933.  
  934. ;  *****      Enter here on exit hooks from Terminal Emulator     *****
  935.  
  936. Our_entry_point:
  937.     cld            ; Forwards
  938.     or ah, ah        ; Is the code 0 (keyboard)?
  939.      jnz OEP_1        ;  No
  940.     jmp SHORT NPS_loop    ; Yes, go do our stuff
  941.  
  942. OEP_1:    cmp ah, 1        ; Code 1 (host character)?
  943.      je OEP_3        ;  Yes
  944.  
  945.     cmp ah, 2        ; Code 2 (shutdown)?
  946.      jne OEP_3        ;  No
  947.     jmp NPS_end        ; Yes, close files and be ready to be gone
  948.  
  949. OEP_3:    ret            ; Unknown, do nothing for now
  950.  
  951. NPS_loop:
  952.     call Get_a_char        ; Get the next character
  953.      jc NPS_end        ;  No more, go close the file
  954.  
  955.     mov ah, al        ; Copy to ah
  956.     call OutChr        ; Send this character
  957.      jmp NPS_end        ;  Failed, give up
  958.  
  959.     ret            ; Return to terminal emulator for now
  960.  
  961. NPS_end:
  962.     sub ax, ax        ; Make a zero
  963.     call Set_up_script_processor ; Make emulator forget us
  964.  
  965.     mov bx, TakAdr        ; Addr of TAKE frame
  966.     mov bx, WORD PTR [bx].TakFcb+1 ; This is where file handle is stored
  967.     mov ah, CLOSE2        ; Close file the file handle way
  968.     int Dos
  969.  
  970.     dec TakLev        ; Untake this file
  971.     sub TakAdr, SIZE TakInfo ; Back off space on stack also
  972.     ret            ; Done here
  973.  
  974. Get_a_char:
  975.     mov bx, TakAdr        ; Addr of our TAKE frame
  976.     mov ax, [bx].TakCnt    ; Get low half of doubleword char count
  977.     or ax, [bx].TakCnt+2    ; Merge with high half of doubleword
  978.      jz GAC_EOF        ;  No chars left, flag as end-of-file
  979.  
  980.     cmp [bx].TakChl, 0    ; Disk file, any chars left in buffer?
  981.      jne GAC_2        ;  Yes, don't need more yet
  982.  
  983.     call TakRd        ; Reload buffer from disk file
  984.     cmp [bx].TakChl, 0    ; Any chars now?
  985.      je GAC_EOF        ;  No chars even after call to TakRd, EOF!
  986.  
  987. GAC_2:    dec [bx].TakChl        ; Decrement for the char
  988.     sub [bx].TakCnt, 1    ; DEC doesn't set carry!!
  989.     sbb [bx].TakCnt+2, 0
  990.  
  991.     mov si, [bx].TakPtr    ; Pick up ptr into buffer
  992.     lodsb            ; Pick up next char
  993.     mov [bx].TakPtr, si    ; Store the updated ptr
  994.  
  995.     cmp al, Lf        ; Is this a linefeed?
  996.      jne GAC_3        ;  No
  997.  
  998.     cmp LastChar, Cr    ; Was the previous character a return?
  999.      jne GAC_3        ;  This Lf was not preceded by a Cr
  1000.  
  1001.     mov LastChar, al    ; Update this
  1002.     jmp Get_a_char        ; Char is Lf following Cr, so don't send it
  1003.  
  1004. GAC_3:    mov LastChar, al    ; Update this for next time
  1005.     cmp al,CtlZ        ; Maybe control-z?
  1006.      je GAC_EOF        ;  Yes, bomb out
  1007.  
  1008.     clc            ; No error
  1009.     ret
  1010.  
  1011. GAC_EOF:
  1012.     stc            ; Error (EOF)
  1013.     ret
  1014.  
  1015. Non_protocol_send ENDP
  1016.  
  1017.  
  1018. ; take commands from a file, but allow a path name
  1019. Take    PROC
  1020.     cmp taklev,maxtak        ; Hit our limit?
  1021.      jl Take1            ; Continue if still OK
  1022.  
  1023.     mov ah,prstr
  1024.     mov dx,offset erms30        ; Complain
  1025.     int dos
  1026.     jmp RSkp
  1027.  
  1028. Take1:    mov di,takadr
  1029.     add di,size takinfo
  1030.     mov ah,cmtxt
  1031.     lea bx,[di].takbuf        ; convenient place to parse name into
  1032.     mov dx,offset filmsg        ; Help in case user types "?"
  1033.     call comnd
  1034.      jmp RSkp
  1035.  
  1036.     call Setup_take_file        ; Call common routine to do the work
  1037.      jnc TAK_Got_it            ;  Ok so far
  1038.  
  1039.     mov ah,prstr
  1040.     mov dx,offset erms31
  1041.     int dos
  1042.     jmp RSkp
  1043.  
  1044. TAK_Got_it:
  1045.     cmp flags.takflg,0
  1046.      je Take4
  1047.  
  1048.     mov ah,prstr
  1049.     mov dx,offset crlf
  1050.     int dos
  1051.  
  1052. Take4:    jmp rskp
  1053.  
  1054. Take    ENDP
  1055.  
  1056.  
  1057. ; Setup_take_file -- routine to set up a new TAKE file in a new TAKE frame
  1058. ;
  1059. ;  call with ...
  1060. ;    di/ New frame address
  1061. ;    ah/ Length of file name
  1062. ;    [di].TakBuf/ File name with optional path ... SPATH is used to fix up
  1063.  
  1064.     PUBLIC Setup_take_file
  1065.  
  1066. Setup_take_file PROC
  1067.  
  1068.     mov Hold_di, di        ; Save frame address
  1069.     lea si, [di].TakBuf    ; Get buffer back
  1070.     mov bl, ah        ; Length of thing parsed
  1071.     sub bh, bh        ; Zero high half
  1072.     mov BYTE PTR [bx+si], 0    ; Make it ASCIZ
  1073.     mov ax, si        ; Point to name again
  1074.     call SPath        ; Is it around?
  1075.      jc Take2        ;  No, go complain
  1076.  
  1077.     mov dx, ax        ; Point to name from spath
  1078.     mov ax, (Open2*256) + 0    ; DOS 2.0 open call for read
  1079.     int Dos
  1080.      jnc Take3        ; Open ok, keep going
  1081.  
  1082. Take2:    ret            ; Return with carry on ...
  1083.  
  1084. Take3:    inc TakLev        ; Bump our nested TAKE count
  1085.     mov di, Hold_di        ; Restore frame address
  1086.     mov TakAdr, di        ; Advance to next TAKE frame
  1087.  
  1088.     mov BYTE PTR [di].TakFcb, 0FEh ; Mark as 2.0 file descriptor
  1089.     mov WORD PTR [di].TakFcb+1, ax ; Save file descriptor
  1090.     mov bx, ax        ; Need descriptor here
  1091.  
  1092.     mov ax, (LSeek*256) + 2    ; Seek 0 bytes from end
  1093.     sub cx, cx
  1094.     sub dx, dx
  1095.     int Dos
  1096.  
  1097.     mov [di].TakCnt, ax    ; Store length
  1098.     mov [di].TakCnt+2, dx    ;  (doubleword)
  1099.  
  1100.     mov ax, (LSeek*256) + 0    ; Seek back to the beginning
  1101.     sub cx, cx
  1102.     sub dx, dx
  1103.     int Dos
  1104.  
  1105.     call TakRd        ; Get a buffer full of data
  1106.     clc            ; Flag no carry (no error)
  1107.     ret            ; Done here
  1108.  
  1109. Setup_take_file ENDP
  1110.  
  1111.  
  1112. TAKRD    PROC    NEAR
  1113.     push bx
  1114.     push cx
  1115.     push dx
  1116.     mov bx,takadr
  1117.     cmp byte ptr [bx].takfcb,0feh    ; is it a 2.0 file handle?
  1118.     jne takrd1            ; no, handle differently
  1119.     push bx                ; save frame address
  1120.     lea dx,[bx].takbuf        ; buffer to read into
  1121.     mov cx,dmasiz            ; # of bytes to read
  1122.     mov ah,readf2            ; 2.0 read call
  1123.     mov bx,word ptr [bx].takfcb+1    ; file handle is stored here
  1124.     int dos
  1125.     pop bx                ; restore frame address
  1126.     jmp takrd2            ; rejoin common exit
  1127.  
  1128. takrd1:    mov ah,setdma
  1129.     lea dx,[bx].takbuf
  1130.     int dos
  1131.     mov ah,readf
  1132.     lea dx,[bx].takfcb
  1133.     int dos
  1134.     mov ah,setdma
  1135.     lea dx, DTA
  1136.     int dos
  1137. takrd2:    mov [bx].takchl,dmasiz
  1138.     lea ax,[bx].takbuf
  1139.     mov [bx].takptr,ax
  1140.     pop dx
  1141.     pop cx
  1142.     pop bx
  1143.     ret
  1144.  
  1145. TAKRD    ENDP
  1146.  
  1147. ; copy the path into pthbuf
  1148. ; enter with ax/ environment segment address
  1149. ; works in 2.0 only
  1150. getpath    proc    near
  1151.     push    es
  1152.     mov    bx,ds
  1153.     mov    es,bx            ; address data segment
  1154.     mov    bx,offset pthnam    ; thing to find
  1155.     mov    cx,pthlen        ; length of it
  1156.     mov    dx,offset pthbuf    ; place to put it
  1157.     mov    byte ptr pthbuf,0    ; initialize to null..
  1158.     call    getenv            ; get environment value
  1159.     pop    es
  1160.     ret                ; and return
  1161. getpath    endp
  1162.  
  1163. ; copy the comspec into cmspbuf
  1164. ; enter with ax/ environment segment address
  1165. ; works in 2.0 only
  1166. getcsp    proc    near
  1167.     push    es
  1168.     mov    bx,ds
  1169.     mov    es,bx            ; address data segment
  1170.     mov    bx,offset cmspnam    ; thing to find
  1171.     mov    cx,cmsplen        ; length of it
  1172.     mov    dx,offset cmspbuf    ; place to put it
  1173.     call    getenv            ; get environment value
  1174.     pop    es
  1175.     ret                ; and return
  1176. getcsp    endp
  1177.  
  1178. ; find a path variable.  Enter with ax/ environment segment,
  1179. ; bx/ variable to find (incl =), cx/ length of variable name,
  1180. ; dx/ address to store value at
  1181. ; The buffer given in dx is unchanged if the variable isn't found
  1182. getenv    proc    near
  1183.     push    ds
  1184.     push    es
  1185.     mov    es,ax            ; address segment
  1186.     mov    di,0            ; offset in segment
  1187. geten1:    cmp    es:byte ptr [di],0    ; end?
  1188.     je    geten4            ; yes, forget it
  1189.     push    cx            ; save counter
  1190.     push    di            ; and offset
  1191.     mov    si,bx
  1192.     repe    cmpsb            ; is it the one?
  1193.     pop    di
  1194.     pop    cx            ; restore these
  1195.     je    geten2            ; found it, break loop
  1196.     push    cx            ; preserve again
  1197.     mov    cx,0ffffh        ; bogus length
  1198.     mov    al,0            ; marker to look for
  1199.     repne    scasb            ; search for it
  1200.     pop    cx            ; restore length
  1201.     jmp    geten1            ; loop thru rest of environment
  1202. geten2:    add    di,cx            ; skip to definition
  1203.     mov    si,di            ; this is source
  1204.     mov    di,dx            ; destination as given
  1205.     mov    ax,ds
  1206.     mov    bx,es
  1207.     mov    ds,bx
  1208.     mov    es,ax            ; exchange segment regs for copy
  1209. geten3:    lodsb                ; get a byte
  1210.     stosb                ; drop it off
  1211.     cmp    al,0            ; end of string
  1212.     jne    geten3            ; no, go on
  1213. geten4:    pop    es
  1214.     pop    ds            ; restore registers
  1215.     ret                ; and return
  1216. getenv    endp
  1217.  
  1218.  
  1219.  %OUT >> About half way through source file
  1220.  
  1221.  
  1222. ; Put xxxxxxxx.INI onto Take stack if it exists.  Just like
  1223. ;  the Take command, except it doesn't read a filename
  1224.  
  1225. RdInit    PROC
  1226.  
  1227.     mov bx, TakAdr        ; Pick up "current" take address
  1228.     add bx, SIZE TakInfo    ; Bump to next frame
  1229.     mov si, OFFSET IniNm2    ; Name to try
  1230.     lea di, [bx].TakBuf    ; Ptr to where to put it
  1231.     mov cx, IniNm2_len    ; Length of name
  1232.     cld            ; Forwards
  1233.     rep movsb        ; Copy the string
  1234.  
  1235.     mov di, bx        ; Copy pointer to TAKE frame to di
  1236.     mov ah, IniNm2_len    ; Length in ah
  1237.  
  1238.     call Setup_take_file    ; Call common routine to do the work
  1239.      jnc RDI_Got_it        ;  Ok so far
  1240.  
  1241.     ret            ; If no file, give up !
  1242.  
  1243. RDI_Got_it:
  1244.     jmp rskp
  1245.  
  1246. RdInit    ENDP
  1247.  
  1248.  
  1249. ; get command line into a macro buffer
  1250.  
  1251. gcmdlin    proc    near
  1252.     push    ds
  1253.     push    es
  1254.     cld
  1255.     mov    es,psp            ; address psp
  1256.     mov    ch,0
  1257.     mov    cl,es:[cline]        ; length of cmd line
  1258.     mov    di,cline+1        ; point to actual line
  1259.     mov    al,' '
  1260.     jcxz    gcmdl3            ; no command line, forget it
  1261.     repe    scasb            ; skip over spaces
  1262.     je    gcmdl3            ; all spaces, forget it
  1263.     mov    si,di            ; this is first non-space
  1264.     dec    si            ; pre-incremented..
  1265.     inc    cx
  1266.     inc    taklev            ; bump take level
  1267.     add    takadr,size takinfo    ; address new take frame
  1268.     mov    bx,takadr
  1269.     mov    byte ptr [bx].takfcb,0ffh ; mark as a macro
  1270.     push    cx            ; save length
  1271.     push    ds            ; and segment
  1272.     lea    di,[bx].takbuf        ; into take buffer
  1273.     mov    ax,ds
  1274.     mov    ds,psp
  1275.     mov    es,ax            ; switch segments for copy
  1276. gcmdl1:    lodsb                ; get a byte
  1277.     cmp    al,','            ; comma?
  1278.     jne    gcmdl2            ; no, keep going
  1279.     mov    al,cr            ; convert to cr
  1280. gcmdl2:    stosb                ; deposit it
  1281.     loop    gcmdl1            ; copy whole cmd
  1282.     pop    ds            ; restore segment
  1283.     pop    cx            ; restore len
  1284.  
  1285.     lea    ax,[bx].takbuf
  1286.     mov    [bx].takptr,ax        ; init buffer ptr
  1287.     mov    [bx].takchl,cl        ; chars remaining
  1288.     mov    [bx].takcnt,cx        ; and all chars
  1289.     mov    [bx].takcnt+2,0        ; clear high order
  1290. gcmdl3:    pop    es
  1291.     pop    ds
  1292.     ret
  1293. gcmdlin    endp
  1294.  
  1295. ;    This routine prints the prompt and specifies the reparse address
  1296.  
  1297. PROMPT    PROC  NEAR
  1298.     mov comand.cmprmp,dx    ; save the prompt
  1299.     pop bx            ; Get the return address
  1300.     mov comand.cmrprs,bx    ; Save as addr to go to on reparse
  1301.     mov comand.cmostp,sp    ; Save for later restoral
  1302.     push bx            ; Put it on the stack again
  1303.     mov bx,offset comand.cmdbuf
  1304.     mov comand.cmcptr,bx    ; Initialize the command pointer
  1305.     mov comand.cmdptr,bx
  1306.     mov ah,0
  1307.     mov comand.cmaflg,ah    ; Zero the flags
  1308.     mov comand.cmccnt,ah
  1309.     mov comand.cmsflg,0FFH
  1310.     cmp flags.takflg,0    ; look at take flag
  1311.     jne promp1        ; supposed to echo, skip this check..
  1312.     cmp taklev,0        ; inside a take file?
  1313.     je promp1        ; no, keep going
  1314.  
  1315.     ret            ; yes, return
  1316.  
  1317. promp1:    mov ah,prstr        ; Print the prompt
  1318.     mov dx,comand.cmprmp
  1319.     int dos
  1320.  
  1321.     ret
  1322.  
  1323. PROMPT    ENDP
  1324.  
  1325. ; Erase specified file(s)
  1326. DELETE    PROC    NEAR
  1327.     mov comand.cmcr,0    ; Filename must be specified
  1328.     mov ah,cmifi        ; Parse an input filespec
  1329.     mov dx,offset fcb
  1330.     mov bx,offset filhlp2    ; Text of help message
  1331.     call comnd
  1332.      jmp r            ; Bad filename
  1333.     mov ah,cmcfm        ; Parse a confirm
  1334.     call comnd
  1335.      jmp r
  1336.     mov flags.nmoflg, 0    ; Function CMIFI leaves this set, clear it
  1337.     cld
  1338.     mov di,offset fcb+1
  1339.     mov al,'?'
  1340.     mov cx,11        ; # of chars in a name
  1341.     repe scasb        ; are they all ?'s?
  1342.     jne del1        ; no, skip message
  1343.     mov dx,offset infms1
  1344.     call prompt
  1345.     mov ah,cmkey
  1346.     mov dx,offset yestab
  1347.     mov bx,0
  1348.     call comnd
  1349.      jmp r
  1350.     push bx
  1351.     mov ah,cmcfm
  1352.     call comnd
  1353.      pop bx
  1354.      ret
  1355.      nop
  1356.     pop bx
  1357.     cmp bx,0
  1358.     jne del1
  1359.     jmp rskp
  1360. del1:    mov dx,offset fcb
  1361.     mov ah,sfirst        ; See if any files match this specification
  1362.     int dos
  1363.     cmp al,0FFH        ; No matches?
  1364.     jne del2
  1365.     mov ah,prstr
  1366.     mov dx,offset erms32
  1367.     int dos
  1368.     jmp rskp
  1369. del2:    mov dx,offset fcb
  1370.     mov ah,delf        ; Erase the file(s)
  1371.     int dos
  1372.     mov dx,offset infms8
  1373.     mov ah,prstr        ; Say we did so
  1374.     int dos
  1375.     jmp rskp
  1376. DELETE    ENDP
  1377.  
  1378.  
  1379. CHKDSK    PROC
  1380.  
  1381.     mov ah,cmcfm
  1382.     call comnd
  1383.      jmp r
  1384.  
  1385.     mov ah, PrStr            ; Code to type string
  1386.     mov dx, OFFSET CrLf        ; A CrLf
  1387.     int Dos                ; Type it
  1388.  
  1389.     mov si,offset chkdcmd        ; point to cmd
  1390.     mov cx,chkdlen            ; and length
  1391.     jmp crun            ; and go execute it nicely
  1392.  
  1393. CHKDSK    ENDP
  1394.  
  1395.  
  1396. DIRECT    PROC
  1397.     mov ah,dosver        ; See what level of DOS we're at
  1398.     int dos
  1399.     cmp al,0        ; Level 2.0 or above?
  1400.     jne dir4        ; Yes - get directory the easy way
  1401.     mov comand.cmcr,1    ; Allow plain CR (so DIR == DIR *.*)
  1402.     mov ah,cmifi        ; Get input file spec
  1403.     mov dx,offset fcb    ; Give the address for the FCB
  1404.     mov bx,offset filhlp3
  1405.     call comnd
  1406.      jmp r
  1407.     mov ah,cmcfm        ; Parse a confirm
  1408.     call comnd
  1409.      jmp r
  1410.     mov comand.cmcr,0    ; Reset this
  1411.     push es
  1412.     mov ax,ds
  1413.     mov es,ax
  1414.     mov temp1,0FFH
  1415.     mov di,offset nambuf
  1416. dir0:    call getfn        ; Get a matching file name
  1417.     cmp al,0FFH        ; Retcode -- are we done?
  1418.     je dir1            ; Yes, just leave
  1419.     call dumpit        ; Print it or dump to buffer
  1420.     jmp dir0
  1421. dir1:    pop es
  1422.     jmp rskp
  1423.  
  1424. dir4:    mov si,offset cmspbuf    ; command processor
  1425.     mov di,offset dirnam
  1426. dir5:    lodsb            ; get a byte
  1427.     or al,al
  1428.     jz dir6            ; stop on the null
  1429.     stosb            ; otherwise copy it in
  1430.     jmp dir5        ; and keep going
  1431. dir6:    mov si,offset dircmd    ; add directory command to it
  1432.     mov cx,dirclen
  1433.     rep movsb
  1434.     mov ah,cmtxt        ; parse with cmtxt so we can have paths..
  1435.     mov bx,di        ; next available byte
  1436.     mov dx,offset filwmsg    ; In case user wants help
  1437.     mov Hold_di, di
  1438.     call comnd
  1439.      jmp r
  1440.     mov di, Hold_di
  1441.     mov cl,ah
  1442.     mov ch,0        ; length of name
  1443.     sub di,offset dirnam    ; compute # of bytes used
  1444.     add cx,di
  1445.     mov si,offset dirnam    ; dir cmd
  1446.     jmp crun        ; join run cmd from there
  1447. DIRECT    ENDP
  1448.  
  1449. getfn:    cmp temp1,0FFH
  1450.     jne gtfn1
  1451.     mov ah,sfirst        ; Any matches?
  1452.     mov dx,offset fcb
  1453.     int dos
  1454.     cmp al,0FFH        ; Means no matches
  1455.     je gtfn5
  1456.     call savfcb
  1457.     mov temp1,0
  1458.     jmp gtfn4
  1459. gtfn1:    cmp flags.wldflg,0FFH    ; Wilcard seen?
  1460.     je gtfn2        ; Yes, get next file
  1461.     mov al,0FFH        ; No, set retcode
  1462.     ret
  1463. gtfn2:    call rstfcb
  1464.     mov ah,snext
  1465.     mov dx,offset fcb
  1466.     int dos
  1467.     cmp al,0        ; Any more matches?
  1468.     je gtfn3        ; Yes keep going
  1469.     mov al,0FFH        ; OK return code
  1470.     ret
  1471. gtfn3:    call savfcb
  1472. gtfn4:    push di
  1473.     mov si,offset DTA    ; Data is here
  1474.     mov di,offset fcb    ; Copy to here
  1475.     mov cx,37
  1476.     repne movsb
  1477.     pop di
  1478.     call nicnam        ; Make name nice for printing
  1479.     mov al,0
  1480.     ret
  1481. gtfn5:    mov ah,prstr        ; Don't print if a server
  1482.     mov dx,offset erms32    ; Say no matches
  1483.     int dos
  1484.     mov al,0FFH        ; Failure return code
  1485.     ret
  1486.  
  1487. savfcb:    push di
  1488.     mov si,offset fcb    ; Data is here
  1489.     mov di,offset cpfcb    ; Copy to here
  1490.     mov cx,37
  1491.     repne movsb
  1492.     pop di
  1493.     ret
  1494.  
  1495. rstfcb:    push di
  1496.     mov si,offset cpfcb    ; Data is here
  1497.     mov di,offset fcb    ; Copy to here
  1498.     mov cx,37
  1499.     repne movsb
  1500.     pop di
  1501.     ret
  1502.  
  1503. nicnam:    mov al,CR        ; Add CRLF before print names
  1504.     stosb
  1505.     mov al,LF
  1506.     stosb
  1507.     mov cx,8
  1508.     mov si,offset fcb+1
  1509.     repne movsb        ; Get the file name
  1510.     mov al,' '
  1511.     stosb
  1512.     mov cx,3
  1513.     repne movsb
  1514.     mov al,tab
  1515.     stosb
  1516.     mov al,' '
  1517.     stosb
  1518.     mov ah,openf
  1519.     mov dx,offset fcb
  1520.     int dos
  1521.     mov bx,offset fcb+18    ; Get hi order word of file size
  1522.     mov ax,[bx]
  1523.     mov dx,ax
  1524.     mov bx,offset fcb+16    ; Get lo order word
  1525.     mov ax,[bx]
  1526.     call nout2x        ; Get it in decimal
  1527.     mov al,tab
  1528.     stosb
  1529.     mov al,' '
  1530.     stosb
  1531.     mov ah,0
  1532.     mov si,offset fcb+20
  1533.     lodsb
  1534.     mov fildat+1,al
  1535.     lodsb
  1536.     mov fildat,al        ; Date field of fcb
  1537.     mov cl,5
  1538.     shr fildat+1,cl
  1539.     and fildat,1
  1540.     mov cl,3
  1541.     shl fildat,cl
  1542.     mov al,fildat
  1543.     or al,fildat+1        ; Get the month field
  1544.     cmp al,9
  1545.     jg nic0
  1546.     push ax
  1547.     mov al,' '
  1548.     stosb
  1549.     pop ax
  1550. nic0:    call nout2        ; Make it decimal
  1551.     mov al,'-'
  1552.     stosb
  1553.     mov si,offset fcb+20    ; Get date field
  1554.     lodsb
  1555.     and al,1FH
  1556.     cmp al,10        ; Only one digit?
  1557.     jge nic0x
  1558.     push ax
  1559.     mov al,'0'        ; Make it two digits
  1560.     stosb
  1561.     pop ax
  1562. nic0x:    call nout2        ; Make it decimal
  1563.     mov al,'-'
  1564.     stosb
  1565.     mov si,offset fcb+21    ; Get the year field
  1566.     lodsb
  1567.     shr al,1
  1568.     add al,80
  1569.     cmp al,100        ; At the year 2000 or above?
  1570.     js nic0y        ; No, just go on
  1571.     sub al,100        ; Go back to two digits
  1572. nic0y:    cmp al,10        ; Only one digit?
  1573.     jge nic0z
  1574.     push ax
  1575.     mov al,'0'        ; Make it two digits
  1576.     stosb
  1577.     pop ax
  1578. nic0z:    call nout2        ; Make it decimal
  1579.     mov al,tab
  1580.     stosb
  1581.     mov si,offset fcb+23    ; Get time field of fcb
  1582.     lodsb
  1583.     mov cl,3        ; Get the hour field
  1584.     shr al,cl
  1585.     mov tmp,'a'        ; For AM
  1586.     cmp al,12        ; Before noon?
  1587.     jl nic1
  1588.     mov tmp,'p'        ; It's PM
  1589.     je nic1            ; Don't change "12" to "0"
  1590.     sub al,12        ; Use a 12 hr. clock
  1591. nic1:    cmp al,0        ; Just after midnight?
  1592.     jne nic1x
  1593.     add al,12        ; Make it "12" instead of "0"
  1594. nic1x:    cmp al,10        ; Pad with a space?
  1595.     jge nic2
  1596.     push ax
  1597.     mov al,' '
  1598.     stosb
  1599.     pop ax
  1600. nic2:    call nout2        ; Make it decimal
  1601.     mov al,':'        ; Separate hours and minutes
  1602.     stosb
  1603.     mov si,offset fcb+23    ; Get the minutes field
  1604.     lodsb
  1605.     and al,07
  1606.     mov cl,3
  1607.     shl al,cl
  1608.     mov ah,al
  1609.     mov si,offset fcb+22
  1610.     lodsb
  1611.     mov cl,5
  1612.     shr al,cl
  1613.     or al,ah
  1614.     mov ah,0
  1615.     cmp al,10        ; Would there be a leading zero
  1616.     jge nic3
  1617.     push ax
  1618.     mov al,'0'
  1619.     stosb
  1620.     pop ax
  1621. nic3:    call nout2        ; Make it decimal
  1622.     mov al,tmp        ; Add 'a' (AM) or 'p' (PM)
  1623.     stosb
  1624.     mov ah,closf
  1625.     mov dx,offset fcb
  1626.     int dos
  1627.     ret
  1628.  
  1629. ; For now, just print it
  1630. dumpit:    mov al,'$'
  1631.     stosb
  1632.     mov ah,prstr
  1633.     mov dx,offset nambuf
  1634.     int dos
  1635.     mov di,offset nambuf
  1636.     ret
  1637.  
  1638. ; Push to an inferior command parser
  1639.  
  1640. DoPush    PROC
  1641.  
  1642.     mov    ah,cmcfm        ; Confirm the command
  1643.     call    comnd
  1644.      jmp    r
  1645.  
  1646.  
  1647. ; Entry to pre-confirmed Push command ...
  1648. ;  so we can Push from FT screen, for example ...
  1649.  
  1650. Quick_Push:
  1651.     mov    si,offset cmspbuf    ; name of parser
  1652.     push    si            ; save beginning
  1653.     sub    cx,cx            ; initial length
  1654. dopus2:    lodsb
  1655.     inc    cx            ; count this
  1656.     or    al,al            ; at end?
  1657.     jnz    dopus2            ; no, keep going
  1658.     pop    si            ; restore cmd
  1659.     dec    cx            ; this is incremented one over
  1660.     jmp    short crun        ; go run it
  1661. dopush    endp
  1662.  
  1663. ; crun - run an arbitrary program.  Enter with si/address of whole
  1664. ; cmd, cx/length of cmd
  1665. CRUN    proc    near
  1666.     push cx            ; save length of cmd
  1667.     mov ax,ds
  1668.     mov es,ax        ; address dest segment
  1669.     mov di,offset nambuf
  1670.     rep movsb        ; copy command so we can mess with it
  1671.     pop cx
  1672.     mov si,offset nambuf    ; point to command
  1673.     jmp short run3        ; and join run code
  1674. CRUN    ENDP
  1675.  
  1676. RUN    PROC    NEAR
  1677.     mov ah,cmtxt        ; Get program name
  1678.     mov bx,offset nambuf    ; Convenient buffer
  1679.     mov dx,offset filmsg    ; In case user wants help
  1680.     call comnd
  1681.      nop
  1682.      nop
  1683.      nop
  1684.     cmp ah,0
  1685.     jne run2
  1686.     mov ah,prstr
  1687.     mov dx,offset erms35
  1688.     int dos
  1689.     jmp rskp
  1690. run2:    mov cl,ah
  1691.     mov ch,0
  1692.     mov si,offset nambuf
  1693.  
  1694. ; alternate entry if cmd is already known.  Source cmd ptr in si
  1695. ; is trashed
  1696. run3:    mov bx,cx
  1697.     mov byte ptr [si+bx],cr    ; end string with a cr for dos
  1698.     mov di,offset cmdnam
  1699.     mov ax,ds
  1700.     mov es,ax
  1701. run4:    lodsb
  1702.     cmp al,' '
  1703.     jne run5
  1704.     dec si            ; back up over space
  1705.     jmp short run6        ; and exit loop
  1706. run5:    stosb
  1707.     loop run4
  1708. run6:    mov byte ptr [di],0    ; terminate string
  1709.     dec si            ; point back a byte into argument
  1710.     mov [si],cl        ; put length of argument here
  1711.     mov exearg+2,si        ; pointer to argument string
  1712.     mov exearg+4,ds        ; segment of same
  1713.     inc si            ; pass length over
  1714.     mov al,1        ; scan leading separators
  1715.     mov di,offset exefcb    ; parse into this fcb
  1716.     mov ah,prsfcb
  1717.     int dos            ; go parse the fcb
  1718.     mov al,1        ; scan leading separators
  1719.     mov di,offset exefcb2    ; second fcb to fill
  1720.     mov ah,prsfcb
  1721.     int dos            ; parse the fcb
  1722.     mov ax,ds
  1723.     mov es,ax        ; put es segment back
  1724.     mov ax,offset cmdnam    ; point to cmd name again
  1725.     call spath        ; look for it
  1726.      jc run8        ;  not found, go complain
  1727.     mov dx,ax        ; point to command name
  1728.  
  1729.  
  1730.     call Restore_normal_error_handling ; Return to normal error handler
  1731.  
  1732. ; At this point, we are about to run the program.  But first, save the
  1733. ;  current settings of the three "user vectors", "Terminate", "Ctrl-Break Exit"
  1734. ;  and "Critical Error Handler".  Seems DOS 2.0 and 2.1 don't restore them
  1735. ;  properly after this call.   The program worked under DOS 3.0 and 3.1
  1736. ;  without this code
  1737.  
  1738.     push es            ; First, save the incoming es
  1739.  
  1740.     mov ax, 3522h        ; Code to Get Vector, starting at 22h
  1741.     int Dos            ; Get it
  1742.  
  1743.     push es            ; Save his segment
  1744.     push bx            ;  and offset
  1745.  
  1746.     inc al            ; 23h -- second vector to get
  1747.     int Dos            ; Get it
  1748.  
  1749.     push es            ; Save his segment
  1750.     push bx            ;  and offset
  1751.  
  1752.     inc al            ; 24h -- third vector to get
  1753.     int Dos            ; Get it
  1754.  
  1755.     push es            ; Save his segment
  1756.     push bx            ;  and offset
  1757.  
  1758.  
  1759. ; Run the program
  1760.  
  1761.     mov ax, ds        ; Copy ds
  1762.     mov es, ax        ;  to es
  1763.     mov ax, (256*Exec)+0    ; Code to load and execute a program
  1764.     mov bx, OFFSET exearg    ; Point to arguments
  1765.     mov ssave, sp        ; Save stack ptr
  1766.     int Dos            ; Go run the program
  1767.  
  1768.  
  1769. ; Just came back from (maybe) running the program, have to restore some
  1770. ;  fundamental items first
  1771.  
  1772.     mov ax,seg datas
  1773.     mov ds, ax        ; reset data segment
  1774.  
  1775.     mov ax,seg stack
  1776.     mov ss,ax        ; and stack segment
  1777.     mov sp,ssave        ; restore stack ptr
  1778.  
  1779.  
  1780. ; Now restore the things DOS 2.0 and 2.1 let be clobbered
  1781.  
  1782.     mov ah, 25h        ; Code to Set Interrupt Vector
  1783.     mov al, 24h        ; Vector to restore
  1784.     pop dx            ; Get back offset
  1785.     pop ds            ; Get back segment
  1786.     int Dos            ; Set it up
  1787.  
  1788.     mov al, 23h        ; Vector to restore
  1789.     pop dx            ; Get back offset
  1790.     pop ds            ; Get back segment
  1791.     int Dos            ; Set it up
  1792.  
  1793.     mov al, 22h        ; Vector to restore
  1794.     pop dx            ; Get back offset
  1795.     pop ds            ; Get back segment
  1796.     int Dos            ; Set it up
  1797.  
  1798.     pop es            ; Get back saved es reg
  1799.     mov ax, SEG DataS    ; DS just got clobbered
  1800.     mov ds, ax        ; Fix it up again
  1801.  
  1802.     call Set_up_error_handling ; Establish our routine as the one to use
  1803.  
  1804.     pushf            ; Save flags
  1805.     mov ah, SetDMA
  1806.     mov dx, OFFSET DTA
  1807.     int Dos            ; Restore DTA address!!
  1808.     popf            ; Recover flags
  1809.  
  1810.      jc Run8        ;  Error
  1811.  
  1812.     mov ah, PrStr
  1813.     mov dx, OFFSET CrLf
  1814.     int Dos            ; Type another blank line
  1815.  
  1816.     jmp rskp        ; Return
  1817.  
  1818. run8:    mov ah,prstr
  1819.     mov dx,offset erms37
  1820.     int dos
  1821.  
  1822.     jmp rskp
  1823.  
  1824. RUN    ENDP
  1825.  
  1826. ; the show command
  1827. showcmd    proc    near
  1828.     mov    ah,cmkey
  1829.     mov    dx,offset shotab
  1830.     xor    bx,bx            ; no canned help
  1831.     call    comnd
  1832.      jmp    r
  1833.     call    bx            ; call the handler
  1834.      jmp    r
  1835.     jmp    rskp            ; and return
  1836. showcmd    endp
  1837.  
  1838.     PUBLIC IntBrk
  1839.  
  1840. IntBrk    PROC FAR
  1841.  
  1842.     push ax            ; Interrupt routine, not allowed to
  1843.     push ds            ;  clobber registers
  1844.     pushf            ; Save flags also
  1845.  
  1846.     mov ax, SEG Datas
  1847.     mov ds, ax
  1848.  
  1849.     cmp flags.debug, 1    ; Debug mode?
  1850.      je IntB2        ;  Yes, then don't ignore the ^C
  1851.  
  1852.     mov flags.cxzflg, 'C'    ; Say we saw a ^C
  1853.     mov pack.state, 'A'    ; Set the state to abort
  1854.     popf            ; Restore flags
  1855.     pop ds            ; Restore regs
  1856.     pop ax
  1857.  
  1858.     cmp ah, 09h        ; Were we typing a string?
  1859.      jne IntBl1        ;  No
  1860.  
  1861.     add sp, 6        ; We want to return to AFTER the "int Dos" that
  1862.                 ;  started us typing ... otherwise this call
  1863.                 ;  retypes the string completely!
  1864.  
  1865. IntBl1:    iret            ; That's it for this ^C
  1866.  
  1867. IntB2:    popf            ; Restore flags
  1868.     pop ds            ; Restore regs
  1869.     pop ax
  1870.     jmp in3ad        ; Original break interrupt address
  1871.  
  1872. IntBrk    ENDP
  1873.  
  1874.  
  1875. ; Set the maximum data packet size. [21b]
  1876.  
  1877. PACKLEN    PROC    NEAR
  1878.     mov ah,trans.spsiz    ; Maximum send packet size
  1879.     sub ah,4        ; Size minus control info
  1880.     sub ah,trans.chklen    ; And minus checksum chars
  1881.     sub ah,2        ; Leave room at end: 2 for possible #X
  1882.     cmp trans.ebquot,'N'    ; Doing 8-bit quoting?
  1883.     je pack0        ; Nope so we've got our size
  1884.     cmp trans.ebquot,'Y'
  1885.     je pack0        ; Not doing it in this case either
  1886.     sub ah,1        ; Another 1 for 8th-bit quoting
  1887. pack0:    mov trans.maxdat,ah    ; Save max length for data field
  1888.     ret
  1889. PACKLEN    ENDP
  1890.  
  1891. NOUT2    PROC    NEAR
  1892.     push ax
  1893.     push dx
  1894.     mov temp,10        ; Divide quotient by 10
  1895.     cwd            ; Convert word to doubleword
  1896.     div temp        ; AX <-- Quo, DX <-- Rem
  1897.     cmp ax,0        ; Are we done?
  1898.     jz nout0        ; Yes
  1899.     call nout2        ; If not, then recurse
  1900. nout0:    add dl,'0'        ; Make it printable
  1901.     mov temp,ax
  1902.     mov al,dl
  1903.     stosb
  1904.     mov ax,temp
  1905.     pop dx
  1906.     pop ax
  1907.     ret            ; We're done. [21c]
  1908. NOUT2    ENDP
  1909.  
  1910. NOUT2X    PROC    NEAR
  1911.     push ax
  1912.     push dx
  1913.     push cx
  1914.     mov temp,10        ; Divide quotient by 10
  1915.     div temp        ; AX <-- Quo, DX <-- Rem
  1916.     mov cx,dx        ; Remember the remainder
  1917.     cmp ax,0        ; Are we done?
  1918.     jz nout0x        ; Yes
  1919.     mov dx,0
  1920.     call nout2        ; If not, then recurse
  1921. nout0x:    add cl,'0'        ; Make it printable
  1922.     mov temp,ax
  1923.     mov al,cl
  1924.     stosb
  1925.     mov ax,temp
  1926.     pop cx
  1927.     pop dx
  1928.     pop ax
  1929.     ret            ; We're done. [21c]
  1930. NOUT2X    ENDP
  1931.  
  1932. SPATH    PROC
  1933.  
  1934. ; enter with ax/ ptr to file name.  Searches path for given file,
  1935. ; returns with ax/ ptr to whole name, or carry on if file isn't
  1936. ; to be found
  1937.  
  1938. ; First, see if file is in connected directory
  1939.  
  1940.     push ax
  1941.     call isfile        ; See if file exists in current dir
  1942.     pop ax            ; AX is clobbered
  1943.      jc spath_0        ;  Not here, look down PATH ...
  1944.  
  1945.     jmp SPath_Exit        ; That was easy ... found file
  1946.  
  1947. spath_0:
  1948.     push    es
  1949.     mov    bx,ds
  1950.     mov    es,bx        ; address data segment
  1951.     mov    bx,ax        ; convenient place to keep this
  1952.     mov    si,ax
  1953.     mov    di,offset tfile ; place to copy to
  1954.     mov    dl,0        ; no '\' seen yet
  1955.     mov    ah,swchar    ; get switch character
  1956. spath1:    lodsb
  1957.     stosb
  1958.     cmp    al,ah        ; contain path characters?
  1959.     jne    spath2        ; no, keep going
  1960.     mov    dl,1        ; remember we've seen them
  1961. spath2:    or    al,al
  1962.     jnz    spath1        ; copy name in
  1963.     or    dl,dl        ; look at flag
  1964.     jz    spath3        ; no path embedded, keep going
  1965.     pop    es
  1966.     mov    ax,offset tfile    ; else..
  1967.     call    isfile
  1968.     mov    ax,offset tfile    ; point to right thing..
  1969.     jmp SPath_Exit        ; let isfile decide and return
  1970.  
  1971. ; no path, keep going
  1972. spath3:    mov    si,offset pthbuf ; path definition
  1973.     cmp    byte ptr [si],0    ; empty path?
  1974.     jne    spath4        ; no, keep going
  1975.     mov    ah,gcd        ; get current dir
  1976.     mov    dl,0        ; for default drive
  1977.     mov    si,offset defpth+1 ; place to put it
  1978.     int    dos
  1979.     mov    si,offset defpth ; point to the path
  1980.  
  1981. spath4:    cmp    byte ptr [si],0    ; null, exit loop
  1982.     je    spath9
  1983.     mov    di,offset tfile    ; place to put name
  1984.  
  1985. spath5:    lodsb            ; get a byte
  1986.     cmp    al,';'        ; end of this part?
  1987.     je    spath7        ; yes, break loop
  1988.     cmp    al,0        ; maybe end of string?
  1989.     jne    spath6        ; no, keep going
  1990.     dec    si        ; back up over it
  1991.     jmp    short spath7    ; and break loop
  1992.  
  1993. spath6:    stosb            ; else stick in dest string
  1994.     jmp    spath5        ; and continue
  1995.  
  1996. spath7:    push    si        ; save this ptr
  1997.     mov    si,bx        ; this is user's file name
  1998.     mov    al,swchar    ; get switch character
  1999.     cmp    byte ptr [di-1],al ; does it end with switch char?
  2000.     je    spath8        ; yes, don't put one in
  2001.     stosb            ; else add one
  2002.  
  2003. spath8:    lodsb
  2004.     stosb
  2005.     or    al,al
  2006.     jnz    spath8        ; copy rest of name
  2007.     pop    si        ; restore pos in path def
  2008.     mov    ax,offset tfile
  2009.     call    isfile        ; is it a file?
  2010.     jc    spath4        ; no, keep looking
  2011.     mov    ax,offset tfile
  2012.     pop    es
  2013.     jmp SPath_Exit        ; return success (carry off)
  2014.  
  2015. spath9:    pop    es        ; restore this
  2016.     mov    ax,bx        ; not found yet, get original path
  2017.     call    isfile        ; does it exist?
  2018.  
  2019. SPath_Exit:
  2020.     ret
  2021.  
  2022. spath    endp
  2023.  
  2024.  
  2025. Set_up_error_handling PROC
  2026.  
  2027.     cmp Error_handling_installed, 0 ; Have this in already?
  2028.      jne SUE_Z        ;  Yes, quit
  2029.  
  2030.     mov Error_handling_installed, 1 ; Flag as already done
  2031.  
  2032.     pushf            ; Save these regs
  2033.     push ax
  2034.     push bx
  2035.     push dx
  2036.  
  2037.     push es            ; Save starting value of es
  2038.     mov ax, 3524h        ; Code to get current interrupt vector 24h
  2039.     int Dos            ; Get address of this interrupt
  2040.  
  2041.     mov WORD PTR cs:Critical, bx ; Store offset (IP)
  2042.     mov ax, es        ; Copy es to ax
  2043.     mov WORD PTR cs:Critical+2, ax ; Store the segment (CS)
  2044.     pop es            ; Get back normal es
  2045.  
  2046.     push ds            ; Save ds
  2047.     mov ax, cs        ; Copy cs ...
  2048.     mov ds, ax        ;  ... to ds
  2049.     mov ax, 2524h        ; Install new addr for int 24
  2050.     mov dx, OFFSET Handle_error ; Addr of routine
  2051.     int Dos            ; Store addr of our routine for this interrupt
  2052.     pop ds            ; Restore ds
  2053.  
  2054.     pop dx            ; Restore regs
  2055.     pop bx
  2056.     pop ax
  2057.     popf
  2058.  
  2059. SUE_Z:    ret
  2060.  
  2061. Set_up_error_handling ENDP
  2062.  
  2063.  
  2064. Restore_normal_error_handling PROC
  2065.  
  2066.     cmp Error_handling_installed, 0 ; Anything to undo?
  2067.      je RNE_Z        ;  No, quit
  2068.  
  2069.     mov Error_handling_installed, 0 ; Flag as back to normal
  2070.  
  2071.     pushf            ; Save these regs
  2072.     push ax
  2073.     push dx
  2074.     push ds
  2075.  
  2076.     mov dx, WORD PTR cs:Critical ; Set up the offset
  2077.     mov ax, WORD PTR cs:Critical+2 ; Set up the segment
  2078.     mov ds, ax        ;  in ds ...
  2079.  
  2080.     mov ax, 2524h        ; Code to set interrupt vector 24h
  2081.     int Dos            ; Store addr of original routine
  2082.  
  2083.     pop ds            ; Restore regs
  2084.     pop dx
  2085.     pop ax
  2086.     popf
  2087.  
  2088. RNE_Z:    ret
  2089.  
  2090. Restore_normal_error_handling ENDP
  2091.  
  2092.  
  2093.     PUBLIC Handle_error, Get_Error
  2094. ;    PUBLIC Set_up_error_handling
  2095. ;    PUBLIC Restore_normal_error_handling
  2096.  
  2097. Handle_error PROC FAR
  2098.  
  2099.     push bx            ; Save bx
  2100.     mov bx, di        ; Copy di to bx
  2101.     sub bh, bh        ; Clear the high half
  2102.     mov CS:Last_Critical_Error, bx ; Save for non-interrupt level rtns
  2103.     or ah, ah        ; Test for disk errors
  2104.      js Not_disk        ;  It isn't disk
  2105.  
  2106.     cmp bl, 0        ; Compare with code for "Write protect"
  2107.      je Fail_It        ;  Yes, make the original DOS call fail
  2108.     cmp bl, 2        ; Compare with code for "Drive not ready"
  2109.      je Fail_It        ;  Yes, make the original DOS call fail
  2110.     jmp SHORT As_usual    ; Treat it like any error
  2111.  
  2112. Not_disk:
  2113.     cmp bl, 09h        ; Compare with code for "Printer out of paper"
  2114.      je Fail_It        ;  Yes, make the original DOS call fail
  2115.     cmp bl, 0Ah        ; Compare with code for "Write fault"
  2116.      je Fail_It        ;  Yes, make the original DOS call fail
  2117. ;    jmp SHORT As_Usual    ; Fall thru to ...
  2118.  
  2119. As_Usual:
  2120.     pop bx            ; Restore bx
  2121.     jmp cs:Critical        ; Go run original critical error handler
  2122.  
  2123. Fail_It:
  2124.     pop bx            ; Restore bx
  2125.  
  2126. ; We must now set things up as if the original function call had failed ...
  2127.  
  2128.     add sp, 6        ; Flush DOS's 24h return regs
  2129.  
  2130. ; IBM PC-DOS 2.0 manual (page D-7) says that you can "return to the program
  2131. ;  immediately after the INT 21 that experienced the error.  Note that if
  2132. ;  this is done, DOS will be in an unstable state until a function call
  2133. ;  higher than 12 is issued."
  2134. ; Based on this warning, lets do a harmless high numbered DOS call
  2135. ;  to "stabilize" DOS
  2136.  
  2137.     mov ah, 30h        ; Code to get vendor number
  2138.     int Dos            ; Ask Dos to stabilize itself
  2139.  
  2140. ; Restore registers to what they were before the "failing" call
  2141.  
  2142.     pop ax
  2143.     pop bx
  2144.     pop cx
  2145.     pop dx
  2146.     pop si
  2147.     pop di
  2148.     mov bp, sp        ; Copy stack ptr to bp
  2149.     or WORD PTR [bp+10], 1    ; Turn on carry bit also, to cover all cases
  2150.     pop bp            ; Then restore real bp
  2151.     pop ds
  2152.     pop es
  2153.     mov al, 0FFh        ; Set up al to look like a failure
  2154.     iret            ; Return from interrupt to the original
  2155.                 ;  "failing" Dos call
  2156.  
  2157. Handle_error ENDP
  2158.  
  2159.  
  2160. Get_Error PROC
  2161.  
  2162.     mov ax, Last_Critical_Error ; Pick this up
  2163.     mov Last_Critical_Error, 0FFh ; Make this impossible
  2164.     ret            ; Run with it
  2165.  
  2166. Get_Error ENDP
  2167.  
  2168.  
  2169. ;   Returns with carry off if the file pointed to by ax exists
  2170.  
  2171. isfile    PROC
  2172.     mov    dx,ax        ; copy ptr
  2173.     mov    ax, (chmod*100h)+0 ; chmod function, read file attribute
  2174.     int    dos
  2175.     ret            ; dos sets carry
  2176. isfile    endp
  2177.  
  2178.  
  2179. ; Get_memory_block -- Get a single block of memory
  2180. ;
  2181. ; Call with ...
  2182. ;    bx/ number of paragraphs of memory requested
  2183. ;
  2184. ; Returns with ...
  2185. ;    carry flag set if failure
  2186. ;    ax/ high-order 16 bits of address of block if success
  2187.  
  2188. Get_memory_block PROC
  2189.  
  2190.     mov ax, Count_of_allocated_blocks ; Get current index
  2191.     cmp ax, Max_count_of_blocks ; Too high?
  2192.      jae GMB_bomb        ;  Too many already
  2193.  
  2194.     mov ah, 48h        ; Code to get a memory block
  2195.     int Dos            ; Ask DOS for the memory
  2196.      jc GMB_bomb        ;  No such luck
  2197.  
  2198.     mov bx, Count_of_allocated_blocks ; Get current index
  2199.     shl bx, 1        ; Double for word offset
  2200.     mov Block_table[bx], ax    ; Store ptr to the block
  2201.     inc Count_of_allocated_blocks ; Update index
  2202.     ret            ; Done here
  2203.  
  2204. GMB_bomb:
  2205.     stc            ; Set error flag if not already set
  2206.     ret            ; Return failure
  2207.  
  2208. Get_memory_block ENDP
  2209.  
  2210.  
  2211. ; Return_memory_block -- Return a single block of memory
  2212. ;
  2213. ; Call with ...
  2214. ;    bx/ high-order 16 bits of address of block to be returned
  2215.  
  2216. Return_memory_block PROC
  2217.     ret            ; Not sure we need this routine
  2218. Return_memory_block ENDP
  2219.  
  2220.  
  2221. ; Return_all_memory -- Return all allocated blocks of memory
  2222.  
  2223. Return_all_memory PROC
  2224.  
  2225.     push es            ; We modify es
  2226.     mov cx, Count_of_allocated_blocks ; The number of blocks we have
  2227.     jcxz RAM_done        ; Done if no blocks
  2228.     sub bx, bx        ; Start at index zero
  2229.  
  2230. RAM_loop:
  2231.     mov ax, Block_table[bx] ; Get the next entry
  2232.     mov es, ax        ; Copy to es
  2233.     mov ah, 49h        ; Code to Free Allocated Memory
  2234.     int Dos            ; Ask DOS to release this memory
  2235.  
  2236.     inc bx            ; Move to word in table
  2237.     inc bx
  2238.     loop RAM_loop        ; Go do the next one if any
  2239.  
  2240. RAM_done:
  2241.     pop es            ; Restore es
  2242.     mov Count_of_allocated_blocks, cx ; Zero the count of blocks
  2243.     ret            ; Go home
  2244.  
  2245. Return_all_memory ENDP
  2246.  
  2247.  
  2248. ; Routines to disable and reenable interrupts
  2249.  
  2250. NoInt    PROC
  2251.  
  2252.     cli            ; We want interrupts off
  2253.     inc NoInt_Count        ; Bump our nested count
  2254.     ret            ; That's it
  2255.  
  2256. NoInt    ENDP
  2257.  
  2258. OkInt    PROC
  2259.  
  2260.     dec NoInt_Count        ; Unbump our nested count
  2261.      jnz OkInt_unchanged    ;  Still nested in a NOINT, just return
  2262.  
  2263.     sti            ;  Back to unnested state, turn ints back on
  2264.  
  2265. OkInt_unchanged:
  2266.     ret            ; Done here
  2267.  
  2268. OkInt    ENDP
  2269.  
  2270.  
  2271. ; Jumping to this location is like retskp.  It assumes the instruction
  2272. ;   after the call is a jmp addr
  2273.  
  2274. RSKP    PROC    NEAR
  2275.     pop bp
  2276.     add bp,3
  2277.     push bp
  2278. ;    ret
  2279. RSKP    ENDP
  2280.  
  2281. ; Jumping here is the same as a ret
  2282.  
  2283. R    PROC    NEAR
  2284.     ret
  2285. R    ENDP
  2286.  
  2287. Code    ENDS            ; End of code section
  2288.  
  2289. Stack   SEGMENT PARA STACK 'STACK'
  2290.     DW 512 DUP(?)        ; Our stack
  2291. Stk    EQU THIS WORD
  2292. Stack   ENDS
  2293.  
  2294.     END Start
  2295.